package framework.ioc.container;

import framework.exception.IsInterfaceOrAbstractException;
import framework.util.ClassReflectUtil;
import test.util.Test;

import java.lang.reflect.InvocationTargetException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author 马洁
 * @date 2020/3/12 - 13:44
 */
public class HashMapObjectPoolSingleton implements ObjectPool {
    public static final int DEFAULT_INIT_MAP_SIZE = 16;
    private Map<Class<?>, Object> objectMap;

    private HashMapObjectPoolSingleton() {
        objectMap = new HashMap<>(HashMapObjectPoolSingleton.DEFAULT_INIT_MAP_SIZE);
    }

    public static HashMapObjectPoolSingleton getInstance() {
        return SingletonHolder.OBJECT_POOL;
    }

    @Override
    public Object getClassInstance(Class<?> cls) {
        if (ClassReflectUtil.isInterfaceAndAbstract(cls)) {
            throw new IsInterfaceOrAbstractException();
        }
        try {
            if (objectMap.containsKey(cls)) {
                return objectMap.get(cls);
            } else {
                Object object = cls.getConstructor().newInstance();

                objectMap.put(cls, object);
                return object;
            }
        } catch (InstantiationException e) {
            Test.p("对象池错误");
            e.printStackTrace();
        } catch (IllegalAccessException illegalEx) {
            Test.p("权限不足");
            illegalEx.printStackTrace();
        } catch (InvocationTargetException invocationEx) {
            Test.p("该类中的方法有错误且未被捕获");
            invocationEx.printStackTrace();
        } catch (NoSuchMethodException noSuchMeEx) {
            Test.p("该类无法被实例化，或者没有指定类型的构造器可以实例化");
            noSuchMeEx.printStackTrace();
        }
        Test.p("错误的类为" + cls);
        return null;
    }

    @Override
    public Object getClassInstance(Class<?> cls, Object[] initArgs) {
        try {
            return objectMap.containsKey(cls) ?
                    objectMap.get(cls) :
                    objectMap.put(cls,
                            cls.getConstructor(getInitClassTypeArray(initArgs)).newInstance(initArgs));
        } catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
            Test.p("对象池错误");
            e.printStackTrace();
            return null;
        }
    }

    private Class<?>[] getInitClassTypeArray(Object[] initArgs) {
        return Arrays.stream(initArgs)
                .map(Object::getClass)
                .collect(Collectors.toUnmodifiableList())
                .toArray(new Class<?>[initArgs.length])
                ;
    }

    private static class SingletonHolder {
        private static final HashMapObjectPoolSingleton OBJECT_POOL =
                new HashMapObjectPoolSingleton();
    }
}
